package com.mooc.lib_network;

import android.annotation.SuppressLint;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.arch.core.executor.ArchTaskExecutor;

import com.mooc.lib_network.cache.CacheManager;

import org.jetbrains.annotations.NotNull;
import org.json.JSONException;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

/**
 * @ClassName: Request$
 * @Description: java类作用描述
 * @Author: 魏靳元
 * @CreateDate: 2022/8/15 16:33
 * @UpdateRemark: 更新内容
 * @Version: 1.0
 */
public abstract class Request<T,R extends Request> implements Cloneable {
    protected String mUrl;
    protected HashMap<String,String> headers=new HashMap<>();
    protected HashMap<String,Object> params=new HashMap<>();

    public static final int CACHE_ONLY=1;
    public static final int CACHE_FIRST=2;
    public static final int NET_ONLY=3;
    public static final int NET_CACHE=4;
    private String cacheKey;
    private Type mType;
    private Class mClaz;
    private int cacheStragtegy;

    @IntDef({CACHE_ONLY,CACHE_FIRST,NET_ONLY,NET_CACHE})
    public @interface CacheStrategy{

    }
    public Request(String url){
        //user/list  //无需域名
        mUrl = url;
    }

    public R addHeader(String key,String value){
        headers.put(key, value);
        return (R) this;
    }
    public R addParam(String key,Object value){
        if(value==null){
            return (R) this;
        }
        try {
            if (value.getClass() == String.class) {
                params.put(key, value);
            } else {
                Field field = value.getClass().getField("TYPE");
                Class claz = (Class) field.get(null);
                if (claz.isPrimitive()) {
                    params.put(key, value);
                }
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return (R) this;
    }
    public R setCacheStragtegy(@CacheStrategy  int cacheStragtegy){
        this.cacheStragtegy = cacheStragtegy;
        return (R) this;
    }

    public R setCacheKey(String key){
        this.cacheKey=key;
        return (R)this;
    }

    public R setResponseType(Type type){
        mType = type;
        return (R) this;
    }
    public R setResponseType(Class claz){
        mClaz = claz;
        return (R)this;
    }
    public ApiResponse<T> excute() {
        if (mType == null) {
            throw new RuntimeException("同步方法,response 返回值 类型必须设置");
        }

        if (cacheStragtegy == CACHE_ONLY) {
            return getCache();
        }

        if (cacheStragtegy != CACHE_ONLY) {
            ApiResponse<T> result = null;
            try {
                Response response = getCall().execute();
                result = parseResponse(response, null);
            } catch (IOException e) {
                e.printStackTrace();
                if (result == null) {
                    result = new ApiResponse<>();
                    result.message = e.getMessage();
                }
            }
            return result;
        }
        return null;
    }

    @SuppressLint("RestrictedApi")
    public void excute(JsonCallBack callback){
        if(cacheStragtegy!=NET_ONLY){
            ArchTaskExecutor.getIOThreadExecutor().execute(new Runnable() {
                @Override
                public void run() {
                    ApiResponse<T> response=getCache();
                    if(callback!=null&&response.body!=null){
                        callback.OnCacheSuccess(response);
                    }
                }
            });
        }
        if(cacheStragtegy!=CACHE_ONLY){
            getCall().enqueue(new Callback() {
                @Override
                public void onFailure(@NotNull Call call, @NotNull IOException e) {
                    ApiResponse<T> response=new ApiResponse<>();
                    response.message=e.getMessage();
                    callback.OnError(response);
                }

                @Override
                public void onResponse(@NotNull Call call, @NotNull Response response)  {
                    ApiResponse<T> apiResponse=parseResponse(response,callback);
                    if(!apiResponse.success){
                        callback.OnError(apiResponse);
                    }else {
                        callback.OnSuccess(apiResponse);
                    }
                }
            });
        }
    }

    private ApiResponse<T> getCache() {

        String key= TextUtils.isEmpty(cacheKey)?createCacheKey():cacheKey;
        Object cache = CacheManager.getCache(key);

        ApiResponse<T> response=new ApiResponse<>();
        response.status=304;
        response.message="缓存获取成功";
        response.body= (T) cache;
        response.success=true;
        return response;
    }

    private ApiResponse<T> parseResponse(Response response, JsonCallBack<T> callback) {
        String message=null;
        int status =response.code();
        boolean success=response.isSuccessful();
        ApiResponse<T> result=new ApiResponse<>();
        Convert convert = ApiService.mConvert;
        try {
            String content = Objects.requireNonNull(response.body()).string();
            Log.i("OnCacheSuccess", "excute: "+content);
            if(success){
                if(callback!=null){
                    ParameterizedType type = (ParameterizedType) callback.getClass().getGenericSuperclass();
                    Type argument = type.getActualTypeArguments()[0];
                    result.body = (T) convert.convert(content, argument);
                }else if(mType!=null){
                    result.body = (T) convert.convert(content, mType);
                }else if(mClaz!=null){
                    result.body = (T) convert.convert(content, mClaz);
                }else {
                    Log.e("request", "parseResponse:无法解析 ");
                }
            }else {
                message=content;
            }
        } catch (IOException e) {
          message=e.getMessage();
          success=false;
        }
        result.success=success;
        result.status=status;
        result.message=message;
        if(result.success && result.body instanceof Serializable && cacheStragtegy != NET_ONLY){
            saveCache(result.body);
        }
        return result;
    }

    private void saveCache(T body) {
        String key= TextUtils.isEmpty(cacheKey)? createCacheKey(): cacheKey;
        CacheManager.saveCache(key, body);
    }

    private String createCacheKey() {
        cacheKey=Urlsplicing.createUrlFromParams(mUrl, params);
        return cacheKey;
    }

    private Call getCall() {


        okhttp3.Request.Builder builder = new okhttp3.Request.Builder();
        addHeaders(builder);

        okhttp3.Request request=generateRequest(builder);

        return ApiService.okHttpClient.newCall(request);
    }

    protected abstract okhttp3.Request generateRequest(okhttp3.Request.Builder builder) ;

    private void addHeaders(okhttp3.Request.Builder builder) {
        for (Map.Entry<String, String> stringStringEntry : headers.entrySet()) {
            builder.addHeader(stringStringEntry.getKey(), stringStringEntry.getValue());
        }
    }
    @NonNull
    @Override
    public Request clone() throws CloneNotSupportedException {
        return (Request<T, R>) super.clone();
    }
} 
